package com.spring.framework.config.async.annotation;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author xuweizhi
 * @since 2020/12/15 10:34
 */
@Configuration
@EnableAsync
@SuppressWarnings("all")
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"com.spring.framework.config.async.annotation"})
public class AsyncConfigExample {

	public static class CustomerAsync {
		public static void main(String[] args) {
			AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AsyncConfigExample.class);
			AsyncMethod asyncMethod = applicationContext.getBean(AsyncMethod.class);
			System.out.println(asyncMethod.getClass());
			System.out.println("--------" + Thread.currentThread().getName() + "--------");
			asyncMethod.log();
			asyncMethod.log2();
		}
	}

	public static class FutureTask {
		/**
		 * 1. 无返回值的异步方法，异常不能被封装，也不会被直接抛出，而是需要通过异常处理器处理.
		 * 2. 默认异常处理器是SimpleAsyncUncaughtExceptionHandler，它的逻辑是直接在调用对应方法的线程中通过error级别日志打印这个异常信息。
		 * 3. 对于Java配置，可以通过重写AsyncConfigurer的getAsyncUncaughtExceptionHandler方法返回一个AsyncUncaughtExceptionHandler异常处理器。
		 * 4. 具有返回值的异步方法执行过程中产生的异常会被封装到Future中，因此很方法方便处理，它的get()方法就能抛出在执行过程中捕获的异常。
		 */
		public static void main(String[] args) throws ExecutionException, InterruptedException {
			AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ConfigurationStart.class);

			FutureTaskMethod futureTaskMethod = ac.getBean(FutureTaskMethod.class);
			System.out.println(futureTaskMethod.getClass());
			System.out.println("--------" + Thread.currentThread().getName() + "--------");
			/*
			 * 1 future
			 */
			Future<Integer> future = futureTaskMethod.future(0);
			System.out.println("FutureTask中获取结果并进行操作的线程: " + Thread.currentThread().getName());
			//get()方法只能同步获取执行结果并进行其他操作，因此可能还是会阻塞调用线程，或者需要手动新开线程等待结果，功能比较简陋
			System.out.println(future.get() + 10);
			System.out.println("返回的Future :" + future);

			/*
			 * 2 completableFuture
			 */
			CompletableFuture<Integer> integerCompletableFuture = futureTaskMethod.completableFuture(1);
			//注册一个正常回调函数，当执行完毕时自动回调该函数，参数就是执行结果，这样就不必同步等待了
			integerCompletableFuture.thenApplyAsync(integer -> {
				System.out.println("CompletableFuture中获取结果并进行操作的线程:: " + Thread.currentThread().getName());
				System.out.println(integer + 10);
				return null;
			});
			//注册一个异常回调函数，当执行抛出异常时时自动回调该函数
			integerCompletableFuture.exceptionally(throwable -> {
				throwable.printStackTrace();
				return null;
			});

			System.out.println("返回的CompletableFuture :" + integerCompletableFuture);

			/*
			 * 3 listenableFuture
			 */
			ListenableFuture<Integer> integerListenableFuture = futureTaskMethod.listenableFuture(2);
			//注册一个回调函数，具有异常方法和正常方法，当正常执行完毕时自动回调onSuccess，参数就是执行结果，这样就不必同步等待了
			integerListenableFuture.addCallback(new ListenableFutureCallback<Integer>() {
				//执行异常自动回调，onFailure中抛出的异常被忽略
				@Override
				public void onFailure(Throwable o) {
					o.printStackTrace();
				}

				//执行成功自动回调，onSuccess中抛出的异常被忽略
				@Override
				public void onSuccess(Integer o) {
					System.out.println("ListenableFuture中获取结果并进行操作的线程: " + Thread.currentThread().getName());
					System.out.println(o + 10);
				}
			});
			System.out.println("返回的ListenableFuture :" + integerListenableFuture);


			/*
			 * 3 noReturn
			 */
			futureTaskMethod.noReturn(1);

		}
	}
}

